import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import Stats from './stats.module.js'
import MyGeom from './geometry_test.js'
import TestBufferGeometry from "./test_bufferGeometry.js";
import TestVertexColor from './test_vertexColor.js';
import TestNormal from './test_normal.js';
import testArrowClassMain from './test_ArrowFunction.js'

// ----------------------- ES6代码测试 -----------------------
let testArrow = new testArrowClassMain();
testArrow.testArrow();
testArrow.testClass();

// 非全屏布局 可以设置 document.getIDxxxx 来嵌入页面
// const my_canvas_width = 900;
// const my_canvas_height = 900;
// 全屏渲染 使用 document.body.appendChild(renderer.domElement) 添加到body中
const my_canvas_width = window.innerWidth;
const my_canvas_height = window.innerHeight;


// ----------------------- 创建场景----------------------- 
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xf0f0f0); // 浅灰色背景
MyGeom.addSomeGeometry(scene);
// ----------------------- 创建相机 ----------------------- 
// 透视投影相机 参数 : ( fov, aspect, near, far ) aspect是宽高比, 一般设置为Canvas的宽高比
const camera = new THREE.PerspectiveCamera(75, my_canvas_width/my_canvas_height, 0.1, 1000);
// const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);


// ----------------------- 创建渲染器----------------------- 
// const renderer = new THREE.WebGLRenderer({
//     canvas: document.querySelector('#webgl')        // 指定渲染器渲染到的canvas
// });

// 如果使用这个方法, 需要在html中添加一个div, id为div_webgl;
const renderer = new THREE.WebGLRenderer({ antialias: true });       // 如果启动了抗锯齿 会导致网页占用从一般的 32m -> 60m....
// const renderer = new THREE.WebGLRenderer();
// 因为 .domElement 可以获得渲染器生成的canvas元素, 所以可以直接添加到页面中
// document.getElementById( "div_webgl" ).appendChild( renderer.domElement );
document.body.appendChild( renderer.domElement );
renderer.setSize(my_canvas_width, my_canvas_height);

// ----------------------- 创建一个立方体----------------------- 
const geometry = new THREE.BoxGeometry();
// 基础网格材质不受光照影响
// const material = new THREE.MeshBasicMaterial({ color: 0x135299, transparent: true, opacity: 0.5 });
const material_lambert = new THREE.MeshLambertMaterial();
// 受光照影响 -> 漫反射THREE.MeshLambertMaterial; 高光THREE.MeshPhongMaterial; 
// 受光照影响 -> 物理: THREE.MeshStandardMaterial; 金属: THREE.MeshPhysicalMaterial

const material_standard = new THREE.MeshStandardMaterial({
    color: 0x1560bd,
    roughness: 0.1,
    metalness: 0.9
});
// 线框模式
material_standard.wireframe = true;
const cube = new THREE.Mesh(geometry, material_standard);
// -----------------------  创建各种几何体 ----------------------- 
// const geometry_sphere = new THREE.SphereGeometry( 30 );
// scene.add( geometry_sphere );



// ----------------------- 添加光源 ----------------------- 
const point_light = new THREE.PointLight( 0x04A211, 1.0 );
point_light.decay = 1.0;                    // 随距离衰减
point_light.intensity = 200.0;              // 光照强度
point_light.position.set( 0, 20, 10 );       // 光源位置
scene.add( point_light );                   // 相机位置不对会看不到光照效果
// 添加环境光 (不太行 还是会导致旋转时受光面->背光面转换过于生硬 因为使用的是简化光照材质 Lambert)
const ambient_light = new THREE.AmbientLight(0xF13280, 0.4);
scene.add( ambient_light );
// 启用物理正确渲染
renderer.physicallyCorrectLights = true;
renderer.outputEncoding = THREE.sRGBEncoding;
// 添加点光源辅助观察
const point_light_helper = new THREE.PointLightHelper( point_light, /*sphereSize*/ 10 );
scene.add( point_light_helper );
// 添加平行光&平行光辅助
const directional_light = new THREE.DirectionalLight( 0xFFFFFF, 2.0 );
directional_light.position.set( 0, -10, -10 );
// 平行光Target 默认为(0,0,0)
directional_light.target = cube;
directional_light.position.set(  800, 800, 800 );
scene.add( directional_light );
const directional_light_helper = new THREE.DirectionalLightHelper( directional_light, 10 );
scene.add( directional_light_helper );

// ----------------------- 相机参数 ----------------------- 
// 默认位置是坐标原点
// cube.position.set( 0, 10, -20 );
// 相机看向立方体 相机原点与立方体原点重合
camera.position.set(  10, 5, 0 );
camera.lookAt( cube.position );
scene.add(cube);


// ----------------------- 辅助观察坐标系 RGB -> xyz;  默认y轴朝上; ----------------------- 
const axesHelper = new THREE.AxesHelper( 150 );
scene.add( axesHelper );



// ----------------------- 添加相机控制 ----------------------- 
const orbit_ctrls = new OrbitControls( camera, renderer.domElement );
// 如果OrbitControls更改了相机参数, 就重新调用渲染器渲染三维场景
// 不需要自己写事件监听器 渲染循环自己会更新; 单一渲染点使得程序更加流畅
// orbit_ctrls.addEventListener( 'change', function() {
//     renderer.render( scene, camera );
// } )

// ----------------------- 时钟计算帧率 ----------------------- 
const fps_clock = new THREE.Clock();
// ----------------------- 外部模块显示FPS ----------------------- 
let stats = new Stats();
stats.showPanel( 0 );
document.body.appendChild( stats.dom );

// ----------------------- 外部模块添加功能 ----------------------- 
// TestBufferGeometry.testBufferGeometry(scene);
// TestBufferGeometry.testFuncSetInterval();
// TestVertexColor.testShowVertexColor(scene);
TestNormal.testNormalFunc(scene);

// ----------------------- 避免渲染模糊的问题: -----------------------
console.log( "------- 当前屏幕 设备像素比: --------", window.devicePixelRatio );    // 1.25
renderer.setPixelRatio( window.devicePixelRatio );

// ----------------------- 动画循环 ----------------------- 
function animate() {
    stats.begin();

    let delta = fps_clock.getDelta()*1000;      // ms
    // console.log( "两帧间隔", delta, "ms" );
    // console.log( "帧率:", 1000/delta );

    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    // directional_light.position.set(  10*Math.sin(Date.now()/1000), 10, 10*Math.cos(Date.now()/1000) );
    renderer.render(scene, camera);

    stats.end();
    // requestAnimationFrame 会周期性循环执行; 默认每秒钟执行60次, 看性能, 如果屏幕刷新率够高也会到 60帧以上;
    requestAnimationFrame(animate);
}
animate();